package com.piggy.sys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.piggy.common.core.domain.R;
import com.piggy.common.core.utils.PageUtils;
import com.piggy.common.core.web.page.PagePlus;
import com.piggy.common.core.web.page.TableDataInfo;
import com.piggy.oss.cloud.OSSFactory;
import com.piggy.oss.utils.FileUploadUtils;
import com.piggy.sys.api.bo.OssFileUploadBo;
import com.piggy.sys.api.domain.SysOss;
import com.piggy.sys.api.vo.SysOssVo;
import com.piggy.sys.domain.bo.SysOssEditBo;
import com.piggy.sys.domain.bo.SysOssQueryBo;
import com.piggy.sys.mapper.SysOssMapper;
import com.piggy.sys.service.ISysOssService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.piggy.common.core.utils.file.MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION;


/**
 * 文件上传Service业务层处理
 *
 * @author piggy
 * @date 2021-07-20
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysOssServiceImpl extends ServiceImpl<SysOssMapper, SysOss> implements ISysOssService {

    @Override
    public SysOssVo queryById(Long id) {
        return getVoById(id, SysOssVo.class);
    }

    @Override
    public TableDataInfo<SysOssVo> queryPageList(SysOssQueryBo bo) {
        PagePlus<SysOss, SysOssVo> result = pageVo(PageUtils.buildPagePlus(true), buildQueryWrapper(bo), SysOssVo.class);
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<SysOssVo> queryList(SysOssQueryBo bo) {
        return listVo(buildQueryWrapper(bo), SysOssVo.class);
    }

    @Override
    public List<SysOssVo> queryIdList(List<String> idList) {
        if (CollUtil.isEmpty(idList)) {
            return null;
        }
        SysOssQueryBo bo = new SysOssQueryBo().setIdList(idList.stream().map(Long::parseLong).collect(Collectors.toList()));
        List<SysOssVo> voList = listVo(buildQueryWrapper(bo), SysOssVo.class);
        if (CollUtil.isEmpty(voList)) {
            return voList;
        }
        Map<Long, SysOssVo> fileMap = voList.stream().collect(Collectors.toMap(SysOssVo::getId, Function.identity()));
        List<SysOssVo> voList1 = new ArrayList<>();
        for (String id : idList) {
            voList1.add(fileMap.get(Long.parseLong(id)));
        }
        return voList1;
    }

    private LambdaQueryWrapper<SysOss> buildQueryWrapper(SysOssQueryBo bo) {
        LambdaQueryWrapper<SysOss> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getId() != null, SysOss::getId, bo.getId());
        lqw.eq(StrUtil.isNotBlank(bo.getFileType()), SysOss::getFileType, bo.getFileType());
        lqw.like(StrUtil.isNotBlank(bo.getName()), SysOss::getName, bo.getName());
        lqw.like(StrUtil.isNotBlank(bo.getOriginName()), SysOss::getOriginName, bo.getOriginName());
        lqw.like(StrUtil.isNotBlank(bo.getPath()), SysOss::getPath, bo.getPath());
        lqw.eq(StrUtil.isNotBlank(bo.getStatus()), SysOss::getStatus, bo.getStatus());
        lqw.in(CollUtil.isNotEmpty(bo.getIdList()), SysOss::getId, bo.getIdList());
        return lqw;
    }

    private SysOss getByValue(String value) {
        return getOne(new LambdaQueryWrapper<SysOss>().eq(SysOss::getValue, value).last("limit 1"));
    }

    @Override
    public SysOssVo insertByAddBo(SysOssVo bo) {
        SysOss add = BeanUtil.toBean(bo, SysOss.class);
        validEntityBeforeSave(add);
        save(add);
        return BeanUtil.toBean(add, SysOssVo.class);
    }

    @Override
    public Boolean updateByEditBo(SysOssEditBo bo) {
        SysOss update = BeanUtil.toBean(bo, SysOss.class);
        validEntityBeforeSave(update);
        return updateById(update);
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(SysOss entity) {
        //TODO 做一些数据校验,如唯一约束
        baseMapper.insert(entity);
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return removeByIds(ids);
    }

    @SneakyThrows
    @Override
    public SysOssVo uploadFileToCLoud(MultipartFile file) {
        //校验文件大小类型
        FileUploadUtils.assertAllowed(file, DEFAULT_ALLOWED_EXTENSION);
        //上传文件后缀
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        //文件上传返回url
        String path = OSSFactory.build().uploadSuffix(file.getBytes(), suffix);

        return BeanUtil.toBean(saveLog(file, path), SysOssVo.class);
    }

    @SneakyThrows
    @Override
    public SysOssVo uploadFileToCLoud(MultipartFile file, String path) {
        //校验文件大小类型
        FileUploadUtils.assertAllowed(file, DEFAULT_ALLOWED_EXTENSION);
        //文件上传返回url
        path = OSSFactory.build().upload(file.getBytes(), path);

        return BeanUtil.toBean(saveLog(file, path), SysOssVo.class);
    }

    @SneakyThrows
    private SysOss saveLog(MultipartFile file, String path) {
        //大小
        Long size = file.getSize();
        //文件名
        String originName = file.getOriginalFilename();
        //hash256
        String hashCode = DigestUtil.sha256Hex(file.getBytes());

        SysOss oss = getByValue(hashCode);
        if (ObjectUtil.isNotEmpty(oss)) {
            return oss;
        }

        //文件类型
        String extensionName = FileUploadUtils.getExtension(file);
        SysOss sysOss = new SysOss();
        sysOss.setFileType(extensionName);
        sysOss.setOriginName(originName);
        sysOss.setPath(path);
        sysOss.setName(originName);
        sysOss.setUrl(path);
        sysOss.setValue(hashCode);
        sysOss.setSize(size);
        sysOss.setCreateBy("admin");

        String url = Objects.requireNonNull(OSSFactory.build()).buildUrl(path);

        validEntityBeforeSave(sysOss);
        sysOss.setUrl(url);
        return sysOss;
    }

    @Override
    public void delCloudFile(String objectName) {
        OSSFactory.build().delFile(objectName);
    }

    @Override
    public R<SysOssVo> getSysOssById(Long id) {

        return R.ok(queryById(id));
    }

    @Override
    public SysOssVo uploadToCloud(OssFileUploadBo bo) {
        //校验文件大小类型
        String fileName = bo.getFileName();
        String content = bo.getContent();
        byte[] bytes = Base64Utils.decodeFromString(content);
        //文件上传返回url
        String path = OSSFactory.build().uploadSuffix(bytes, fileName);

        return BeanUtil.toBean(saveContent(bytes, path, fileName),SysOssVo.class);
    }

    private SysOss saveContent(byte[] content, String path, String name) {
        //大小
        Long size = Long.valueOf(content.length);
        //hash256
        String hashCode = DigestUtil.sha256Hex(content);

        SysOss oss = getByValue(hashCode);
        if (ObjectUtil.isNotEmpty(oss)) {
            return oss;
        }

        //文件类型
        SysOss sysOss = new SysOss();
        sysOss.setFileType(name);
        sysOss.setOriginName(name);
        sysOss.setPath(path);
        sysOss.setName(name);
        sysOss.setUrl(path);
        sysOss.setValue(hashCode);
        sysOss.setSize(size);
        sysOss.setCreateBy("admin");

        String url = Objects.requireNonNull(OSSFactory.build()).buildUrl(path);

        validEntityBeforeSave(sysOss);
        sysOss.setUrl(url);
        return sysOss;
    }
}
